﻿using System;
using System.IO;

namespace yacomp.helpers
{
    using SanlieHash.OtherHash;
    using System.Text;

    internal partial class helper
    {
        internal static CRC32 crc = new CRC32();
        public static uint calc_crc(Stream sr, long pos, uint length)
        {
            sr.Position = pos;
            crc.New();
            var buf = new byte[1024];
            var len = length >> 10;
            for (; len > 0; len--)
            {
                sr.Read(buf, 0, 1024);
                crc.Update(buf);
            }
            if ((len = length & 1023) > 0)
            {
                buf = new byte[len];
                sr.Read(buf, 0, (int)len);
                crc.Update(buf);
            }

            return crc.MakeUInt32();
        }
        public static uint calc_crc2(Stream sr)
        {
            return calc_crc(sr, sr.Position, (uint)(sr.Length - sr.Position));
        }
        public static uint calc_crc(Stream sr)
        {
            return touint2(calc_crc(sr, sr.Position, (uint)(sr.Length - sr.Position)));
        }
        internal static uint touint2(uint u1)
        {
            return ((u1 >> 24)&0xff) | ((u1 >> 8) & 0xff00) | ((u1 << 8) & 0xff0000) | ((u1 <<24) & 0xff000000);
        }
        internal static void write_crc(Stream sr, long start, uint length)
        {
            uint crc = calc_crc(sr, start, length);
            Write(sr, crc);
        }
        public static void ReadAllToMemory(Stream sr, Stream dst)
        {
            var buf = new byte[1024];
            int len = 1;
            while (sr.CanRead && len!=0) if ((len = sr.Read(buf, 0, 1024)) > 0) dst.Write(buf, 0, len);
            dst.Flush();
        }
        public static void ReadToMemory(Stream sr, Stream dst, uint len)
        {
            var buf = new byte[1024];
            var len2 = len >> 10;
            var len3 = 1024;

            for(; len2 > 0; len2--) if ((len3 = sr.Read(buf, 0, 1024))>0) dst.Write(buf, 0, len3);

            len3 = (int)(len & 1023);
            if (len3 > 0)
            {
                len3 = sr.Read(buf, 0, len3);
                dst.Write(buf, 0, len3);
            }
            dst.Flush();
        }
        public static uint Readuint(Stream sr)
        {
            return (uint)Readint(sr);
        }
        public static int Readint(Stream sr)
        {
            return Readushort(sr) | (int)Readushort(sr)<<16;
        }
        public static string Readchars(Stream sr, int count)
        {
            var text = string.Empty;
            for (; count > 0; count--) text += (char)sr.ReadByte();
            return text;
        }
        public static string Readutf8(Stream s, int count)
        {
            if (count == 0) return string.Empty;
            return System.Text.UTF8Encoding.UTF8.GetString(Readbytes(s, count));
        }
        public static byte[] Readbytes(Stream s, int count)
        {
            var buf = new byte[count];
            s.Read(buf, 0, count);
            return buf;
        }
        public static void Writechars(Stream sr, string chars)
        {
            foreach (var _char in chars) sr.WriteByte((byte)_char);
        }
        public static uint Readuint2(Stream sr)
        {
            return (uint)Readushort2(sr)<<16 | Readushort2(sr);
        }
        public static ulong Readulong2(Stream sr)
        {
            return (ulong)(Readuint2(sr)) << 32 | Readuint2(sr);
        }
        public static ulong Readulong(Stream sr)
        {
            return Readuint(sr) | (ulong)Readuint(sr) << 32;
        }
        public static short Readshort(Stream sr)
        {
            return (short)(sr.ReadByte() | sr.ReadByte() << 8);
        }
        public static ushort Readushort(Stream sr)
        {
            return (ushort)Readshort(sr);
        }
        public static ushort Readushort2(Stream sr)
        {
            return (ushort)Readshort2(sr);
        }
        public static short Readshort2(Stream sr)
        {
            return (short)(sr.ReadByte() << 8 | sr.ReadByte());
        }
        public static decimal Read16Dot16(Stream sr)
        {
            var a = Readushort2(sr);
            var b = Readushort2(sr);
            while (b > 0) b /= 10;
            return a + b;
        }
        public static byte Readbyte(Stream sr)
        {
            return (byte)sr.ReadByte();
        }
        public static void Write(Stream sr, byte value)
        {
            sr.WriteByte(value);
        }
        public static void WriteColor(Stream sr, double color, int bitcount)
        {
            var bytes  = BitConverter.GetBytes((int)color);
            if (bitcount >= 32) helper.Write(sr, bytes[3]);
            if (bitcount >= 24) helper.Write(sr, bytes[2]);
            if (bitcount >= 16) helper.Write(sr, bytes[2]);
            if (bitcount >= 8) helper.Write(sr, bytes[2]);
        }
        public static void Write(Stream sr, uint value)
        {
            sr.WriteByte((byte)value);
            sr.WriteByte((byte)(value>>8));
            sr.WriteByte((byte)(value>>16));
            sr.WriteByte((byte)(value>>24));
        }
        public static void Write2(Stream sr, uint value)
        {
            sr.WriteByte((byte)(value >> 24));
            sr.WriteByte((byte)(value >> 16));
            sr.WriteByte((byte)(value >> 8));
            sr.WriteByte((byte)value);
        }
        public static void write_utf8(Stream sr, string text)
        {
            var buf = UTF8Encoding.UTF8.GetBytes(text);
            sr.Write(buf, 0, buf.Length);
        }
        public static void Write(Stream sr, ushort value)
        {
            sr.WriteByte((byte)value);
            sr.WriteByte((byte)(value >> 8));
        }
        public static void Write2(Stream sr, ushort value)
        {
            sr.WriteByte((byte)(value >> 8));
            sr.WriteByte((byte)value);
        }
        public static void Write(Stream sr, int value)
        {
            sr.WriteByte((byte)value);
            sr.WriteByte((byte)(value >> 8));
            sr.WriteByte((byte)(value >> 16));
            sr.WriteByte((byte)(value >> 24));
        }
        public static void Write2(Stream sr, int value)
        {
            sr.WriteByte((byte)(value >> 24));
            sr.WriteByte((byte)(value >> 16));
            sr.WriteByte((byte)(value >> 8));
            sr.WriteByte((byte)value);
        }
        public static void Write(Stream sr, ulong value)
        {
            sr.WriteByte((byte)value);
            sr.WriteByte((byte)(value >> 8));
            sr.WriteByte((byte)(value >> 16));
            sr.WriteByte((byte)(value >> 24));
            sr.WriteByte((byte)(value >> 32));
            sr.WriteByte((byte)(value >> 40));
            sr.WriteByte((byte)(value >> 48));
            sr.WriteByte((byte)(value >> 56));
        }
        public static void Write2(Stream sr, ulong value)
        {
            sr.WriteByte((byte)(value >> 56));
            sr.WriteByte((byte)(value >> 48));
            sr.WriteByte((byte)(value >> 40));
            sr.WriteByte((byte)(value >> 32));
            sr.WriteByte((byte)(value >> 24));
            sr.WriteByte((byte)(value >> 16));
            sr.WriteByte((byte)(value >> 8));
            sr.WriteByte((byte)value);
        }
        // 向后跳转到标记位
        public static bool goto_flag(Stream s, uint flag)
        {
            var len = s.Length;
            byte[] flags = [(byte)flag, (byte)(flag >> 8), (byte)(flag >> 16), (byte)(flag >> 24)];
            var ix = -1;

            s.Position += 3;
            while (s.Position < len)
            {
                if ((ix = Array.IndexOf(flags, helper.Readbyte(s)))!= -1)
                {
                    s.Position -= ix+1;
                    if (helper.Readuint(s) == flag) return true;
                    s.Position += ix;
                    continue;
                }

                s.Position += 3;
            }
            return false;
        }
        // 向前 跳转到标记位
        public static bool backto_flag(Stream s, uint flag, decimal min= 3)
        {
            byte[] flags = [(byte)flag, (byte)(flag >> 8), (byte)(flag >> 16), (byte)(flag >> 24)];
            var ix = -1;

            while (s.Position > min)
            {
                if ((ix = Array.IndexOf(flags, helper.Readbyte(s))) != -1)
                {
                    s.Position -= ix + 1;
                    if (helper.Readuint(s) == flag) return true;
                    s.Position -= 8-ix;
                    continue;
                }
                s.Position -= 5;
            }
            return false;
        }
        public static bool backto_flag_max65535(Stream s, uint flag)
        {
            return backto_flag(s, flag, s.Position - 0xffff);
        }

        public static byte[] take_utf8_bytes(string text)
        {
            return UTF8Encoding.UTF8.GetBytes(text);
        }
    }
}
